#include "drv_flash.h"

//读取指定地址的字(32位数据) 
//faddr:读地址 
//返回值:对应数据.
u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(__IO uint32_t *)faddr; 
}

//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint16_t STMFLASH_GetFlashSector(u32 addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10; 
	return FLASH_SECTOR_11;	
}


//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(32位)数
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)   	
{
	u32 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
		ReadAddr+=4;//偏移4个字节.	
	}
}

/**
  * @brief  Erases a specified FLASH Sector.
  *
  * @note   If an erase and a program operations are requested simustaneously,    
  *         the erase operation is performed before the program one.
  *
  * @param  FLASH_Sector: The Sector number to be erased.
  *
  *  @note  For STM32F405xx/407xx and STM32F415xx/417xx devices this parameter can 
  *         be a value between FLASH_Sector_0 and FLASH_Sector_11.
  *
  *         For STM32F42xxx/43xxx devices this parameter can be a value between 
  *         FLASH_Sector_0 and FLASH_Sector_23.
  *
  *         For STM32F401xx devices this parameter can be a value between 
  *         FLASH_Sector_0 and FLASH_Sector_5.
  *
  *         For STM32F411xE devices this parameter can be a value between 
  *         FLASH_Sector_0 and FLASH_Sector_7.
  *
  * @param  VoltageRange: The device voltage range which defines the erase parallelism.  
  *          This parameter can be one of the following values:
  *            @arg VoltageRange_1: when the device voltage range is 1.8V to 2.1V, 
  *                                  the operation will be done by byte (8-bit) 
  *            @arg VoltageRange_2: when the device voltage range is 2.1V to 2.7V,
  *                                  the operation will be done by half word (16-bit)
  *            @arg VoltageRange_3: when the device voltage range is 2.7V to 3.6V,
  *                                  the operation will be done by word (32-bit)
  *            @arg VoltageRange_4: when the device voltage range is 2.7V to 3.6V + External Vpp, 
  *                                  the operation will be done by double word (64-bit)
  *       
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PROGRAM,
  *                       FLASH_ERROR_WRP, FLASH_ERROR_OPERATION or FLASH_COMPLETE.
  */
HAL_StatusTypeDef FLASH_EraseSector_Safe(uint32_t FLASH_Sector)
{
    u32 SectorError=0;
    FLASH_EraseInitTypeDef FlashEraseInit={0};
    HAL_StatusTypeDef FlashStatus=HAL_OK;

 	  HAL_FLASH_Unlock();             //解锁	
    HAL_FLASH_OB_Unlock();
    FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型，扇区擦除 
    FlashEraseInit.Sector=FLASH_Sector;   //要擦除的扇区
    FlashEraseInit.NbSectors=1;                             //一次只擦除一个扇区
    FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围，VCC=2.7~3.6V之间!!
    if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK) 
    {
        FlashStatus = HAL_ERROR;//发生错误了  
    }
//    SCB_CleanInvalidateDCache();                            //清除无效的D-Cache
	HAL_FLASH_Lock();           //上锁
	return FlashStatus;
}

//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
	 
//从指定地址开始写入指定长度的数据
//特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
//         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
//         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
//         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. 
//该函数对OTP区域也有效!可以用来写OTP区!
//OTP区域地址范围:0X1FFF7800~0X1FFF7A0F
//WriteAddr:起始地址(此地址必须为4的倍数!!)
//pBuffer:数据指针
//NumToWrite:字(32位)数(就是要写入的32位数据的个数.) 
u8 flash_write_status = 0;
u8 flash_read_status = 0;
u8 write_err[64]={"Flash Program Error!\r\n"};
u8 check_err[64]={"Flash Program Error! Read Check failed!\r\n"};
int STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
{ 
	int bRet = 0;
	u32 *WriteBack = (u32*) WriteAddr;
	u32 *BufferBack = pBuffer;
	u32 endaddr=0;	
	if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)
		return 11;	//非法地址
    HAL_FLASH_Unlock();             //解锁    
//    SCB_CleanInvalidateDCache();                            //清除无效的D-Cache
	
	endaddr=WriteAddr+NumToWrite; //写入的结束地址

//	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)//写数据
		{
      while(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,WriteAddr,*pBuffer)!=HAL_OK)//写入数据
			{
				bRet++;
				//drv_UART1_SendBuffer(write_err, strlen(write_err));
				if(bRet>9)
					break;	//写入异常
			}
			WriteAddr+=4;
			pBuffer++;
		} 
	}
	HAL_FLASH_Lock();           //上锁
	flash_write_status = (u8)bRet;
	//read back check
	if(bRet<10)
	{
		int i;
		bRet = 0;
		for(i=0;i<NumToWrite/4;i++)
		{
			if(WriteBack[i]!=BufferBack[i])
			{
				bRet = 12;//write error
				//drv_UART1_SendBuffer(check_err, strlen(check_err));
				break;
			}
		}
	}
	flash_read_status = (u8)bRet;
	return bRet;//return 0 success 1 fail
} 

